package com.tax.service.impl;

import com.tax.dto.req.CheckValidCodeReq;
import com.tax.dto.res.ValidImgRes;
import com.tax.manager.RedisApiManager;
import com.tax.service.ValidCodeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * FileName: ValidCodeServiceImpl
 * Author:   duandehui
 * Date:     2023/3/4 19:32
 * Description: 图形验证码服务
 */
@Service
@Slf4j
public class ValidCodeServiceImpl implements ValidCodeService {


    @Autowired
    private RedisApiManager redisApiManager;
    @Override
    public ValidImgRes getValidImg() {
        String requestId = UUID.randomUUID().toString().replace("-", "").toUpperCase();
        ValidImgRes ret = new ValidImgRes();
        //在内存中创建图形
        int width = 60, height = 20;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //获取图形上下文
        Graphics g = image.getGraphics();
        SecureRandom random = new SecureRandom();
        //设定背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        //设定字体
        g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
        g.setColor(getRandColor(160, 200));
        //随机产生155条干扰线，使图像中的认证码不易被其他程序测到
        for (int i = 0; i < 255; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        int ipCount = 1;
        StringBuilder verifyCode = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            String rand=randCode(random,ipCount);
            //不要0和字母o
            while("0".equals(rand) || "o".equals(rand) || "O".equals(rand)){
                rand=randCode(random,ipCount);
            }
            verifyCode.append(rand);
            //将认证码显示到图像中
            g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
            //调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
            g.drawString(rand,13*i+6,16);
        }
        //图像生成
        g.dispose();
        //输出图像到页面
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        try {
            ImageIO.write(image,"JPEG",baos);
            byte[] bytes = baos.toByteArray();
            String base64Img="data:image/JPEG;base64,"+new String(Base64.getEncoder().encode(bytes));
            ret.setImg(base64Img);
            ret.setRequestId(requestId);
            String validImgKey = getVimkey(requestId);
            redisApiManager.set(validImgKey,verifyCode.toString(),5, TimeUnit.MINUTES);
            return ret;
        }catch (Exception e){
            log.error("e:{}",e);
            return ret;
        }finally {
            try {
                baos.close();
            } catch (Exception e) {

            }
        }
    }

    @Override
    public String checkValidCode(CheckValidCodeReq req) {
        String requestId = req.getRequestId();
        String validCode = req.getValidCode();
        if (StringUtils.isBlank(requestId)||StringUtils.isBlank(validCode)){
            return "图形验证码不能为空";
        }
        String validImgKey = getVimkey(requestId);
        String existCode = redisApiManager.get(validImgKey);
        if (StringUtils.isBlank(existCode)){
            return "图形验证码已过期";
        }
        if (!existCode.equals(validCode)){
            return "图形验证码错误";
        }
        redisApiManager.remove(validImgKey);
        return null;
    }

    public String getVimkey(String requestId){
        return "vimg:"+requestId;
    }

    private Color getRandColor(int fc, int bc) {
        SecureRandom random = new SecureRandom();
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

    private String randCode(SecureRandom random, int ipCount) {
        String rand = "";
        if (ipCount > 9) {
            //输出字母还是数字
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //字符串
            if ("char".equalsIgnoreCase(charOrNum)) {
                //取得大写字母还是小写字母
                int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
                rand+=(char)(choice+random.nextInt(26));
            } else if ("num".equalsIgnoreCase(charOrNum)) {
                //数字
                rand+=String.valueOf(random.nextInt(10));
            }
        }else {
            rand+=String.valueOf(random.nextInt(10));
        }
        return rand;
    }
}
